package yartiss.engine.simulation.scheduling.policies.tools;

import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.ITaskSet;
import yartiss.engine.simulation.system.SystemMetrics;

public class DPSlackTimeManager2 extends DPSlacktimeManager{

	private long hyperPeriod;
	private ITaskSet taskSet;

	@Override
	public long getSlackTime(long date, ITaskSet taskSet){
		if(this.taskSet != taskSet){
			hyperPeriod = SystemMetrics.hyperPeriod(taskSet);
			System.out.println("hp="+hyperPeriod);
			this.taskSet = taskSet;
		}
		System.out.println("start "+date);
		long st = computeSlackTime(date,taskSet);
		System.out.println("end");
		return st;
	}

	private long computeSlackTime(long absoluteDate, ITaskSet taskSet){
		long date = absoluteDate % hyperPeriod;
		long minX = Long.MAX_VALUE;
		for (ITask task : taskSet) 
			minX = Math.min(minX, task.getPeriod() - task.getDeadline());

		long sumIdles = 0;
		long ki =  hyperPeriod - minX;
		long lastKi = ki , contiguousIdlesSum=0;
		while(ki > date){

			long Fi = hyperPeriod - ki ;
			long idle = 0;
			//System.out.println(ki+" : +++++++date="+date+"+++++++++++++++++");
			for (ITask task : taskSet) {
				long xj = task.getPeriod() - task.getDeadline();
				long t = hyperPeriod - xj - ki;
				long result = t / task.getPeriod();
				if(t > 0){
					result += t % task.getPeriod()==0 ? 0 : 1;
					Fi -= result * task.getWcet();
				}
			}
			Fi -= sumIdles;
			for (ITask task : taskSet) {
				if(task.getNextAbsoluteDeadline(date) > ki){
					Fi += (task.getWcet()-task.getRemainingCost());
				}
			}
			idle = Math.max(0, Fi);
			//System.out.println("ki="+ki+ "==> Di="+idle);
			if(ki+idle == lastKi)contiguousIdlesSum += idle;
			else contiguousIdlesSum = idle;
			sumIdles +=  idle;


			long prevKi = Long.MIN_VALUE;
			for (ITask task : taskSet) {
				long di = task.getPreviousAbsoluteDeadline(ki);
				prevKi = Math.max(prevKi, di);
			}
			
			lastKi = ki;
			if(prevKi < 0 && ki > 0) ki = 0;
			else ki = prevKi;
		}		

		long slack = hyperPeriod-date;
		for (ITask task : taskSet) {
			long xj = task.getPeriod() - task.getDeadline();
			long t = hyperPeriod - xj - date;
			long result = t / task.getPeriod();
			if(t > 0){
				result += (t % task.getPeriod()==0 ? 0 : 1);
				slack -= result * task.getWcet();
			}
		}
		slack -= sumIdles;
		for (ITask task : taskSet) {
			if(task.getNextAbsoluteDeadline(date) > date){
				slack += (task.getWcet()-task.getRemainingCost());
			}
		}
		//System.out.println(" slack="+slack);
		if(slack+date == lastKi)slack += contiguousIdlesSum;
		//System.out.println(date + " : slack="+slack);
		return slack;
	}

}
